//
//  QKGCD.m
//  testTool
//
//  Created by Su on 2019/5/3.
//  Copyright © 2019 com.qiankun. All rights reserved.
//

#import "QKGCD.h"

@implementation QKGCD

- (void)initQKGCD {
    
    
    self.tickt1 = [[NSThread alloc] initWithTarget:self selector:@selector(sallTicket) object:nil];
    self.tickt2 = [[NSThread alloc] initWithTarget:self selector:@selector(sallTicket) object:nil];
    self.tickt3 = [[NSThread alloc] initWithTarget:self selector:@selector(sallTicket) object:nil];
    self.ticketCount = 500;
    
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //    [self.tickt1 start];
    //    [self.tickt2 start];
    //    [self.tickt3 start];
    
    //测试栅格函数
    //[self barrier];
    
    //延时执行
    //    [self disafter];
    
    //一次性函数
    //    [self  onceCode];
    
    // 快速遍历测试
    //    [self quickBlock];
    
    // GCD 队列组
    //    [self GCDWithGroup];
    [self initTicketStatusSave];
    
}
-(void)safeSallTicket{
    self.ticketCount = 50;
    NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
    NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];
    
    queue1.maxConcurrentOperationCount = queue2.maxConcurrentOperationCount = 1;
    
    __weak typeof(self) weakSelf = self;
    
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        [weakSelf sallTicketWithOp];
    }];
    
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        [weakSelf sallTicketWithOp];
    }];
    
    [queue1 addOperation:op1];
    [queue2 addOperation:op2];
    
    
}
-(void)sallTicketWithOp{
    while (1) {
        // 加锁
        [self.lock lock];
        if (self.ticketCount > 0) {
            //如果还有票，继续售卖
            self.ticketCount--;
            NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%zd 窗口:%@", self.ticketCount, [NSThread currentThread]]);
            [NSThread sleepForTimeInterval:0.2];
        }
        // 解锁
        [self.lock unlock];
        if (self.ticketCount <= 0) {
            NSLog(@"所有火车票均已售完");
            break;
        }
        
    }
}


//NSOperation 的线程通信
-(void)opMsg{
    
    //eg:合成图片
    NSBlockOperation *down1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"img1 download");
    }];
    
    NSBlockOperation *down2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"img2 download");
    }];
    
    NSBlockOperation *complate = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"合并 img1 & img2");
    }];
    
    [complate addDependency:down1];
    [complate addDependency:down2];
    
    
    //线程间的基本通信;
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    [queue addOperationWithBlock:^{
        NSURL *url = [NSURL URLWithString:@"remoteImgURL"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            UIImageView *imgview = [UIImageView new];
            imgview.image = image;
        }];
    }];
}


//NSOperation的依赖和监听

-(void)opRelyOnOp{
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"task1");
    }];
    
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"task2");
    }];
    
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"task3");
    }];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    [queue addOperation:op1];
    [queue addOperation:op2];
    [queue addOperation:op3];
    
    /*
     如果想要设置op3依赖op1,2执行完成后执行,可以使用如下的代码:
     也s可以op3 -> op2  -> op1
     但是要注意防止出现循环依赖: op3 -> op2  -> op1 -> op3
     
     # 也可以设置不同队列进行依赖
     queue queue1 两个不同队列之间的任务依赖
     */
    
    [op3 addDependency:op1];
    [op3 addDependency:op2];
    
    /*
     监听操作完成
     */
    
    op3.completionBlock = ^{
        NSLog(@"op3 task finish");
    };
}


//测试并行OperationQueue
-(void)operationQueue{
    /*
     [NSOperationQueue mainQueue]; 如果使用mainqueueu, 那么获取到的是主队列
     如果使用的是alloc 方法获取,那么是 并行
     */
    
    
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    //设置最大并发数量, 值取1的时候可以看做是串行队列
    queue.maxConcurrentOperationCount = 3;
    
    //通过suspened 可以执行挂起; 任务挂起后并咩有消失 , 通过设置suspended = NO. 继续任务
    //注意如果实在自定义的op对象时,是否需要考虑到界面优化
    //queue.suspended = YES;
    
    
    //定义操作任务
    NSInvocationOperation *opOne = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run:) object:@"xiaoxiaosu"];
    NSInvocationOperation *opTwo = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run:) object:@"xiaoxiaosu"];
    
    NSBlockOperation *opBlock = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"opBlock");
    }];
    [opBlock addExecutionBlock:^{
        NSLog(@"opblock add block task");
    }];
    
    //添加任务
    [queue addOperation:opOne];
    [queue addOperation:opTwo];
    [queue addOperation:opBlock];
    
    //还可以通过block直接添加task
    [queue addOperationWithBlock:^{
        
    }];
    //取消所有队列, 注意与suspended的区别 ;
    //    [queue cancelAllOperations];
    
}



//GCD队列组
-(void)GCDWithGroup{
    /*
     合并两张图片或者多个任务处理完成后合并结果
     */
    
    //定义一个c并行队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //创建一个队列组
    dispatch_group_t group = dispatch_group_create();
    
    //异步任务添加到队列组
    dispatch_group_async(group, queue, ^{
        //sub task
    });
    //异步任务添加到队列组
    dispatch_group_async(group, queue, ^{
        //sub task
    });
    //异步任务添加到队列组
    dispatch_group_async(group, queue, ^{
        //sub task ....
    });
    
    //监听队列组各个子任务完成后的合并
    dispatch_group_notify(group, queue, ^{
        // sub task finish
        //TODO
    });
}

//快速遍历
-(void)quickBlock{
    /**
     可以i替代部分for循环的功能;
     eg: w想将一个文件夹中的文件剪切或者拷贝到另外一个文件夹中,如果我们通过for循环
     去做这件事情,当文件数量达到一定的数量的时候效率肯定降低; 但是如果我们使用GCD进行
     处理, 会好很多;
     */
    
    // 使用常规操作移动文件
    // [self  normalMoveFile];
    // 使用 GCD 移动文件
    //    [self applayGCDMoveFile];
    
    
}

//使用 GCD 移动文件, 快速遍历
-(void)applayGCDMoveFile{
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 常规操作
    NSFileManager *mgr = [NSFileManager defaultManager];
    NSString *fromPath = @"/User/su/Desktop/Form";
    NSString *toPath = @"/User/su/Desktop/To";
    NSArray *subPaths = [mgr subpathsAtPath:fromPath];
    
    dispatch_apply(subPaths.count, queue, ^(size_t index) {
        NSString *subPath = subPaths[index];
        NSString *fromFullPath = [fromPath stringByAppendingPathComponent:subPath];
        NSString *toFullPath = [toPath stringByAppendingPathComponent:subPath];
        [mgr moveItemAtPath:fromFullPath toPath:toFullPath error:nil];
    });
}

//常规移动文件操作
-(void)normalMoveFile{
    // 常规操作
    NSFileManager *mgr = [NSFileManager defaultManager];
    NSString *fromPath = @"/User/su/Desktop/Form";
    NSString *toPath = @"/User/su/Desktop/To";
    NSArray *subPaths = [mgr subpathsAtPath:fromPath];
    
    for (NSString *subPath  in subPaths) {
        NSString *fromFullPath = [fromPath stringByAppendingPathComponent:subPath];
        NSString *toFullPath = [toPath stringByAppendingPathComponent:subPath];
        [mgr moveItemAtPath:fromFullPath toPath:toFullPath error:nil];
    }
}

//一次性函数, 类似单例,资源加载等;注意与懒加载的区别;
-(void)onceCode{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"hhhh");
    });
}

//延时执行
-(void)disafter{
    //延时两秒钟执行 run
    //    [self performSelector:@selector(run:) withObject:@"两好三坏" afterDelay:2];
    
    //可以传入其他队列
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)),
                   dispatch_get_main_queue(), ^{
                       [self run:@"两好三坏"];
                   });
    
    // 使用NSTimer, 作为定时器进行操作
    [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(run:) userInfo:nil repeats:NO];
    
}

//栅格
-(void)barrier{
    /**
     
     不能使用quan'jue'de全局的并发队列. 会出现紊乱
     
     栅格函数使用后, 在栅格函数之前的, 先进行执行;
     在栅格函数之后, 等待栅格函数执行完成后在执行;
     
     */
    dispatch_queue_t queue = dispatch_queue_create("dispatch_barrier", DISPATCH_CURRENT_QUEUE_LABEL);
    
    dispatch_async(queue, ^{
        NSLog(@"---1----%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"---2----%@",[NSThread currentThread]);
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"---barrier----%@",[NSThread currentThread]);
    });
    
    
    dispatch_async(queue, ^{
        NSLog(@"---3----%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"---4----%@",[NSThread currentThread]);
    });
}

-(void)creatSubThredWithNSThred{
    //开启简单事务处理
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"两好三坏"];
    
    //开启隐藏事务
    [self performSelectorInBackground:@selector(run:) withObject:@"xiaoxiaosu"];
    
}

-(void)run:(NSString *)params{
    NSLog(@"%@---",params);
    
}
//出票
-(void)sallTicket{
    
    @synchronized (self) {
        
        while (1) {
            NSInteger count = self.ticketCount;
            if (count>0) {
                self.ticketCount = count - 1;
                
                NSLog(@"--%ld----%@",(long)self.ticketCount,[NSThread currentThread]);
            }else{
                NSLog(@"--无票---");
                break;
            }
        }
    }
    
}



/**
 * 非线程安全：不使用 semaphore
 * 初始化火车票数量、卖票窗口(非线程安全)、并开始卖票
 */
- (void)unSaveTicket{
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"semaphore---begin");
    
    self.ticketCount = 50;
    
    // queue1 代表售卖窗口1
    dispatch_queue_t queue1 = dispatch_queue_create("net.bujige.testQueue1", DISPATCH_QUEUE_SERIAL);
    // queue2 代表售卖窗口2
    dispatch_queue_t queue2 = dispatch_queue_create("net.bujige.testQueue2", DISPATCH_QUEUE_SERIAL);
    
    dispatch_queue_t queue3 = dispatch_queue_create("net.bujige.testQueue2", DISPATCH_QUEUE_SERIAL);
    __weak typeof(self) weakSelf = self;
    dispatch_async(queue1, ^{
        [weakSelf saleTicketunSafe];
    });
    
    dispatch_async(queue2, ^{
        [weakSelf saleTicketunSafe];
    });
    dispatch_async(queue3, ^{
        [weakSelf saleTicketunSafe];
    });
}

/**
 * 售卖火车票(非线程安全)
 */
- (void)saleTicketunSafe {
    while (1) {
        
        if (self.ticketCount > 0) {  //如果还有票，继续售卖
            self.ticketCount--;
            NSLog(@"%@", [NSString stringWithFormat:@"剩余票数：%d 窗口：%@", self.ticketCount, [NSThread currentThread]]);
            [NSThread sleepForTimeInterval:0.2];
        } else { //如果已卖完，关闭售票窗口
            NSLog(@"所有火车票均已售完");
            break;
        }
        
    }
}



/**
 * 线程安全：使用 semaphore 加锁
 * 初始化火车票数量、卖票窗口(线程安全)、并开始卖票
 */
- (void)initTicketStatusSave {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"semaphore---begin");
    self.ticketCount = 50;
    // queue1 代表票售卖窗口1
    dispatch_queue_t queue1 = dispatch_queue_create("com.test.gcd", DISPATCH_QUEUE_SERIAL);
    // queue2 代表售卖窗口2
    dispatch_queue_t queue2 = dispatch_queue_create("com.test.gcd", DISPATCH_QUEUE_SERIAL);
    
    __weak typeof(self) weakSelf = self;
    dispatch_async(queue1, ^{
        [weakSelf saleTicketSafe];
    });
    
    dispatch_async(queue2, ^{
        [weakSelf saleTicketSafe];
    });
}

/**
 * 售卖火车票(线程安全)
 */
- (void)saleTicketSafe {
    while (1) {
        @synchronized (self) {
            if (self.ticketCount > 0) {  //如果还有票，继续售卖
                self.ticketCount--;
                NSLog(@"%@", [NSString stringWithFormat:@"剩余票数：%zd 窗口：%@", self.ticketCount, [NSThread currentThread]]);
            } else { //如果已卖完，关闭售票窗口
                NSLog(@"所有火车票均已售完");
                break;
            }
        }
    }
}

@end
